package com.irdstudio.apicenter.frame.util;

import java.io.File;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tmatesoft.svn.core.SVNCommitInfo;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.core.wc.SVNClientManager;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc.SVNStatus;
import org.tmatesoft.svn.core.wc.SVNUpdateClient;
import org.tmatesoft.svn.core.wc.SVNWCUtil;

/**
 * SVNKit Utility 通过纯Java操作Svn
 * 
 * @author guangming.li
 * @version 1.0
 * @date 2015-08-05
 */
public class SVNUtil {

	/* 日志输出对象 */
	private static Logger logger = LoggerFactory.getLogger(SVNUtil.class);

	/**
	 * 通过不同的协议初始化版本库
	 */
	public static void setupLibrary() {
		DAVRepositoryFactory.setup();
		SVNRepositoryFactoryImpl.setup();
		FSRepositoryFactory.setup();
	}

	/**
	 * 验证SVN地址并登录，返回一个可用的Svn客户端对象
	 * 
	 * @param svnRoot
	 * @param userName
	 * @param password
	 * @return
	 */
	public static SVNClientManager authSvn(String svnRoot, String userName,
			String password) {

		// 初始化版本库
		setupLibrary();

		// 创建库连接
		SVNRepository repository = null;
		try {
			repository = SVNRepositoryFactory.create(SVNURL
					.parseURIEncoded(svnRoot));
		} catch (SVNException e) {
			logger.error(e.getMessage());
			e.printStackTrace();
			return null;
		}

		// 身份验证
		ISVNAuthenticationManager authManager = SVNWCUtil
				.createDefaultAuthenticationManager(userName, password
						.toCharArray());

		// 创建身份验证管理器
		repository.setAuthenticationManager(authManager);

		DefaultSVNOptions options = SVNWCUtil.createDefaultOptions(true);
		SVNClientManager clientManager = SVNClientManager.newInstance(options,
				authManager);
		return clientManager;
	}

	/**
	 * 导出Svn仓库中指定目录
	 * 
	 * @param clientManager
	 * @param url
	 * @param dstPath
	 * @return
	 */
	public static long doExport(SVNClientManager clientManager, SVNURL url,
			File dstPath) {

		SVNUpdateClient updateClient = clientManager.getUpdateClient();
		/*
		 * sets externals not to be ignored during the update 设置外部更新期间不被忽略
		 */
		updateClient.setIgnoreExternals(false);

		/*
		 * returns the number of the revision wcPath was updated to
		 * 修改wcPath更新返回的数量
		 */
		try {
			return updateClient.doExport(url, dstPath, SVNRevision.HEAD,
					SVNRevision.HEAD, "", true, SVNDepth.INFINITY);
		} catch (SVNException e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		}
		return 0;
	}

	/**
	 * 在存储库上创建一个目录 Make directory in svn repository
	 * 
	 * @param clientManager
	 * @param url
	 *            eg: http://svn.ambow.com/wlpt/bsp/trunk
	 * @param commitMessage
	 * @return
	 * @throws SVNException
	 */
	public static SVNCommitInfo makeDirectory(SVNClientManager clientManager,
			SVNURL url, String commitMessage) {
		try {
			return clientManager.getCommitClient().doMkDir(
					new SVNURL[] { url }, commitMessage);
		} catch (SVNException e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 递归提交一个路径（本地目录）到存储库。 Imports an unversioned directory into a repository
	 * location denoted by a destination URL
	 * 
	 * @param clientManager
	 * @param localPath
	 *            a local unversioned directory or singal file that will be
	 *            imported into a repository;
	 * @param dstURL
	 *            a repository location where the local unversioned
	 *            directory/file will be imported into
	 * @param commitMessage
	 * @param isRecursive
	 *            递归
	 * @return
	 */
	public static SVNCommitInfo importDirectory(SVNClientManager clientManager,
			File localPath, SVNURL dstURL, String commitMessage,
			boolean isRecursive) {
		try {
			return clientManager.getCommitClient().doImport(localPath, dstURL,
					commitMessage, null, true, true,
					SVNDepth.fromRecurse(isRecursive));
		} catch (SVNException e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 添加文件、目录到工作副本并且预定添加到存储库。它们会在下次提交上传并添加到存储库中。 Puts directories and files
	 * under version control
	 * 
	 * @param clientManager
	 *            SVNClientManager
	 * @param wcPath
	 *            work copy path
	 */
	public static void addEntry(SVNClientManager clientManager, File wcPath) {
		try {
			clientManager.getWCClient().doAdd(new File[] { wcPath }, true,
					false, false, SVNDepth.INFINITY, false, false, true);
		} catch (SVNException e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		}
	}

	/**
	 * 添加文件、目录到工作副本并且预定添加到存储库。它们会在下次提交上传并添加到存储库中。 Puts directories and files
	 * under version control
	 * 
	 * @param clientManager
	 *            SVNClientManager
	 * @param wcPath
	 *            work copy path
	 */
	public static void doDelete(SVNClientManager clientManager, File wcPath) {
		try {
			clientManager.getWCClient().doDelete(wcPath, true, true, true);
			/*
			 * clientManager.getWCClient().doDelete(new File[] { wcPath }, true,
			 * false, false, SVNDepth.INFINITY, false, false, true);
			 */
		} catch (SVNException e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		}
	}

	/**
	 * 获得一个工作副本条目的状态 Collects status information on a single Working Copy item
	 * 
	 * @param clientManager
	 * @param wcPath
	 *            local item's path
	 * @param remote
	 *            true to check up the status of the item in the repository,
	 *            that will tell if the local item is out-of-date (like '-u'
	 *            option in the SVN client's 'svn status' command), otherwise
	 *            false
	 * @return
	 * @throws SVNException
	 */
	public static SVNStatus showStatus(SVNClientManager clientManager,
			File wcPath, boolean remote) {
		SVNStatus status = null;
		try {
			status = clientManager.getStatusClient().doStatus(wcPath, remote);
		} catch (SVNException e) {
			logger.error("获取svn指定文件的状态异常："+e.getMessage());
			//e.printStackTrace();
			status = null;
		}
		return status;
	}

	/**
	 * 将修改从工作副本提交到存储库。 Commit work copy's change to svn
	 * 
	 * @param clientManager
	 * @param wcPath
	 *            working copy paths which changes are to be committed
	 * @param keepLocks
	 *            whether to unlock or not files in the repository
	 * @param commitMessage
	 *            commit log message
	 * @return
	 * @throws SVNException
	 */
	public static SVNCommitInfo commit(SVNClientManager clientManager,
			File[] wcPath, boolean keepLocks, String commitMessage) {
		try {
			return clientManager.getCommitClient().doCommit(
					wcPath, keepLocks, commitMessage, null,
					null, false, false, SVNDepth.INFINITY);
		} catch (SVNException e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 先添加文件到版本库，再提交到版本库
	 * 
	 * @param clientManager
	 * @param wcPath
	 * @param keepLocks
	 * @param commitMessage
	 * @return
	 */

	public static SVNCommitInfo commitCombination(
			SVNClientManager clientManager, File[] wcPath, boolean keepLocks,
			String commitMessage) {
		try {
			// 先提交到版本库
			clientManager.getWCClient().doAdd(wcPath, true,
					false, false, SVNDepth.INFINITY, false, false, true);
			// 再提交
			return clientManager.getCommitClient().doCommit(
					wcPath, keepLocks, commitMessage, null,
					null, false, false, SVNDepth.INFINITY);
		} catch (SVNException e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 把工作副本更新为最新版本或某个指定版本。 Updates a working copy (brings changes from the
	 * repository into the working copy).
	 * 
	 * @param clientManager
	 * @param wcPath
	 *            working copy path
	 * @param updateToRevision
	 *            revision to update to
	 * @param depth
	 *            update的深度：目录、子目录、文件
	 * @return
	 * @throws SVNException
	 */
	public static long update(SVNClientManager clientManager, File wcPath,
			SVNRevision updateToRevision, SVNDepth depth) {
		SVNUpdateClient updateClient = clientManager.getUpdateClient();

		/*
		 * sets externals not to be ignored during the update
		 */
		updateClient.setIgnoreExternals(false);

		/*
		 * returns the number of the revision wcPath was updated to
		 */
		try {
			return updateClient.doUpdate(wcPath, updateToRevision, depth,
					false, false);
		} catch (SVNException e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		}
		return 0;
	}

	/**
	 * 从存储库中检出工作副本 recursively checks out a working copy from url into wcDir
	 * 
	 * @param clientManager
	 * @param url
	 *            a repository location from where a Working Copy will be
	 *            checked out
	 * @param revision
	 *            the desired revision of the Working Copy to be checked out
	 * @param destPath
	 *            the local path where the Working Copy will be placed
	 * @param depth
	 *            checkout的深度，目录、子目录、文件
	 * @return
	 * @throws SVNException
	 */
	public static long checkout(SVNClientManager clientManager, SVNURL url,
			SVNRevision revision, File destPath, SVNDepth depth) {

		SVNUpdateClient updateClient = clientManager.getUpdateClient();
		/*
		 * sets externals not to be ignored during the checkout
		 */
		updateClient.setIgnoreExternals(false);
		/*
		 * returns the number of the revision at which the working copy is
		 */
		try {
			return updateClient.doCheckout(url, destPath, revision, revision,
					depth, false);
		} catch (SVNException e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		}
		return 0;
	}

	/**
	 * 确定path是否是一个工作空间
	 * 
	 * @param path
	 * @return
	 */
	public static boolean isWorkingCopy(File path) {
		if (!path.exists()) {
			logger.warn("'" + path + "' not exist!");
			return false;
		}
		try {
			if (null == SVNWCUtil.getWorkingCopyRoot(path, false)) {
				return false;
			}
		} catch (SVNException e) {
			logger.error(e.getMessage());
			e.printStackTrace();
		}
		return true;
	}

	/**
	 * 将字符串形式的SVN地址转换为SVN的地址对象
	 * 
	 * @param strUrl
	 * @return
	 */
	public static SVNURL makeSVNURL(String strUrl) {
		SVNURL svnUrl = null;
		try {
			svnUrl = SVNURL.parseURIEncoded(strUrl);
		} catch (SVNException e) {
			e.printStackTrace();
		}
		return svnUrl;
	}

	/**
	 * 递归检查不在版本控制的文件，并add到svn
	 * 
	 * @param clientManager
	 * @param wc
	 */
	public static void checkVersiondDirectory(SVNClientManager clientManager,
			File wc) {
		if (!SVNWCUtil.isVersionedDirectory(wc)) {
			SVNUtil.addEntry(clientManager, wc);
		}
		if (wc.isDirectory()) {
			for (File sub : wc.listFiles()) {
				if (sub.isDirectory() && sub.getName().equals(".svn")) {
					continue;
				}
				checkVersiondDirectory(clientManager, sub);
			}
		}
	}

	/**
	 * 确定一个URL在SVN上是否存在
	 * 
	 * @param url
	 * @return
	 */
	public static boolean isURLExist(SVNURL url, String username,
			String password) {
		try {
			SVNRepository svnRepository = SVNRepositoryFactory.create(url);
			ISVNAuthenticationManager authManager = SVNWCUtil
					.createDefaultAuthenticationManager(username, password
							.toCharArray());
			svnRepository.setAuthenticationManager(authManager);
			SVNNodeKind nodeKind = svnRepository.checkPath("", -1);
			return nodeKind == SVNNodeKind.NONE ? false : true;
		} catch (SVNException e) {
			e.printStackTrace();
		}
		return false;
	}

	public static void main(String[] args) {
		SVNClientManager clientManager = SVNUtil.authSvn(
				"https://192.168.1.125/svn/mobile/maccs", "ligm", "888888");
		SVNURL url = null;
		try {
			url = SVNURL
					.parseURIEncoded("https://192.168.1.125/svn/mobile/maccs");
			// url =
			// SVNURL.parseURIEncoded("https://192.168.1.125/svn/mobile/maota");
		} catch (SVNException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		File destPath = new File("E:/svntest/checkout/client");
		SVNUtil.doExport(clientManager, url, destPath);
		// SVNUtil.checkout(clientManager, url, SVNRevision.HEAD, destPath,
		// SVNDepth.INFINITY);
		// File wcPath=new File("E:/svntest/checkout/client/");
		// SVNUtil.update(clientManager, wcPath, SVNRevision.HEAD,
		// SVNDepth.INFINITY);
		System.out.println("dd");
	}

}
